import json
import os
import csv
import openpyxl
from longguo_ui.config.config import config
import yaml
from typing import List, Dict, Any, Optional


class DataProcessor:
    """数据处理工具类，支持JSON/YAML/CSV/Excel格式的数据读取与处理"""

    @staticmethod
    def load_json_data(file_name: str, key: Optional[str] = None) -> Any:
        """
        读取JSON数据，可指定key提取内容

        :param file_name: JSON文件名（需放在DATA_DIR目录下）
        :param key: 可选，指定要提取的键名
        :return: 解析后的JSON数据（字典/列表）
        :raises Exception: 读取或解析失败时抛出异常
        """
        data_path = os.path.join(config.DATA_DIR, file_name)
        try:
            with open(data_path, 'r', encoding='utf-8') as f:
                data = json.load(f)
                return data.get(key, data) if key else data
        except FileNotFoundError:
            raise Exception(f"JSON文件不存在: {data_path}")
        except json.JSONDecodeError:
            raise Exception(f"JSON格式错误: {data_path}")
        except Exception as e:
            raise Exception(f"JSON读取失败: {str(e)}")

    @staticmethod
    def load_yaml_data(file_name: str, key: Optional[str] = None) -> Any:
        """
        读取YAML数据，可指定key提取内容

        :param file_name: YAML文件名（需放在DATA_DIR目录下）
        :param key: 可选，指定要提取的键名
        :return: 解析后的YAML数据（字典/列表）
        :raises Exception: 读取或解析失败时抛出异常
        """
        data_path = os.path.join(config.DATA_DIR, file_name)
        try:
            with open(data_path, 'r', encoding='utf-8') as f:
                data = yaml.safe_load(f)
                return data.get(key, data) if key and data else data
        except FileNotFoundError:
            raise Exception(f"YAML文件不存在: {data_path}")
        except yaml.YAMLError:
            raise Exception(f"YAML格式错误: {data_path}")
        except Exception as e:
            raise Exception(f"YAML读取失败: {str(e)}")

    @staticmethod
    def load_csv_data(file_name: str) -> List[Dict[str, Any]]:
        """
        读取CSV数据，兼容缺少description字段的情况

        :param file_name: CSV文件名（需放在DATA_DIR目录下）
        :return: 标准化的数据列表，每个元素包含type、data、description
        :raises Exception: 读取失败或字段缺失时抛出异常
        """
        data_path = os.path.join(config.DATA_DIR, file_name)
        data: List[Dict[str, Any]] = []

        try:
            with open(data_path, 'r', encoding='utf-8', newline='') as f:
                reader = csv.DictReader(f)
                headers = reader.fieldnames or []

                # 验证必要字段
                required_fields = ["type", "username", "password"]
                missing_fields = [f for f in required_fields if f not in headers]
                if missing_fields:
                    raise ValueError(f"CSV文件缺少必要字段: {', '.join(missing_fields)}")

                # 读取并处理数据行
                for index, row in enumerate(reader, 1):
                    # 处理空值（替换为空白字符串）
                    processed_row = {k: v.strip() if v else "" for k, v in row.items()}

                    data.append({
                        "type": processed_row["type"],
                        "data": {
                            "username": processed_row["username"],
                            "password": processed_row["password"]
                        },
                        "description": processed_row.get(
                            "description",
                            f"CSV用例 #{index}: {processed_row['type']}登录"
                        )
                    })
            return data
        except FileNotFoundError:
            raise Exception(f"CSV文件不存在: {data_path}")
        except Exception as e:
            raise Exception(f"CSV读取失败: {str(e)}")

    @staticmethod
    def load_excel_data(file_name: str, sheet_name: Optional[str] = None) -> List[Dict[str, Any]]:
        """
        读取Excel数据，支持指定工作表

        :param file_name: Excel文件名（需放在DATA_DIR目录下）
        :param sheet_name: 可选，指定工作表名称，默认读取活动工作表
        :return: 标准化的数据列表，每个元素包含type、data、description
        :raises Exception: 读取失败或字段缺失时抛出异常
        """
        data_path = os.path.join(config.DATA_DIR, file_name)
        data: List[Dict[str, Any]] = []

        try:
            workbook = openpyxl.load_workbook(data_path, read_only=True, data_only=True)
            # 选择工作表
            sheet = workbook[sheet_name] if sheet_name else workbook.active

            # 读取表头（第一行）
            headers = [cell.value.strip() if cell.value else "" for cell in sheet[1]]

            # 验证必要字段
            required_fields = ["type", "username", "password"]
            missing_fields = [f for f in required_fields if f not in headers]
            if missing_fields:
                raise ValueError(f"Excel文件缺少必要字段: {', '.join(missing_fields)}")

            # 读取数据行（从第二行开始）
            for row_num, row in enumerate(sheet.iter_rows(min_row=2, values_only=True), 2):
                row_data = dict(zip(headers, row))

                # 处理空值
                processed_data = {
                    k: str(v).strip() if v is not None else ""
                    for k, v in row_data.items()
                }

                data.append({
                    "type": processed_data["type"],
                    "data": {
                        "username": processed_data["username"],
                        "password": processed_data["password"]
                    },
                    "description": processed_data.get(
                        "description",
                        f"Excel用例 #第{row_num}行: {processed_data['type']}登录"
                    )
                })

            workbook.close()
            return data
        except FileNotFoundError:
            raise Exception(f"Excel文件不存在: {data_path}")
        except KeyError as e:
            raise Exception(f"工作表不存在: {str(e)}")
        except Exception as e:
            raise Exception(f"Excel读取失败: {str(e)}")

    @staticmethod
    def save_json_data(data: Any, file_name: str) -> None:
        """
        保存数据到JSON文件

        :param data: 要保存的数据（可序列化对象）
        :param file_name: 目标文件名
        :raises Exception: 保存失败时抛出异常
        """
        data_path = os.path.join(config.DATA_DIR, file_name)
        try:
            with open(data_path, 'w', encoding='utf-8') as f:
                json.dump(data, f, ensure_ascii=False, indent=2)
        except Exception as e:
            raise Exception(f"JSON保存失败: {str(e)}")


# 实例化供全局使用
data_processor = DataProcessor()